﻿
using System;
using System.Linq;
using Behavioral.Private;

namespace Behavioral
{
    public interface IAction : IActionable, IInitializerMarker, IContextGetter, IContextSetter
    {
        void Execute();
    }

    public interface IAction<TTarget> : IActionable, IInitializerMarker, IContextGetter, IContextSetter
    {
        void Execute(TTarget target);
    }

    public interface IAction<TTarget, TReturnType> : IActionable, IInitializerMarker, IContextGetter, IContextSetter
    {
        TReturnType Execute(TTarget target);
    }

    public interface IActionMutable<TTarget> : IActionable, IInitializerMarker, IContextGetter, IContextSetter
    {
        void Execute(ref TTarget target);
    }

    public interface IActionMutable<TTarget, TReturnType> : IActionable, IInitializerMarker, IContextGetter, IContextSetter
    {
        TReturnType Execute(ref TTarget target);
    }

    namespace Private
    {
        public interface IActionable
        {
        }

        internal class ActionRunner : IContextGetterInternal, IContextSetterInternal
        {
            public void Execute<TAction, TTarget, TReturnType>(TAction action, ref TTarget target, ref TReturnType returnValue)
                where TAction : IActionable
            {
                IAction actionContextFree = action as IAction;
                if (actionContextFree != null)
                {
                    actionContextFree.Execute();
                    return;
                }

                IAction<TTarget> actionWithTarget = action as IAction<TTarget>;
                if (actionWithTarget != null)
                {
                    actionWithTarget.Execute(target);
                    return;
                }

                IActionMutable<TTarget> actionWithMutableTarget = action as IActionMutable<TTarget>;
                if (actionWithMutableTarget != null)
                {
                    actionWithMutableTarget.Execute(ref target);
                    return;
                }

                IAction<TTarget, TReturnType> actionWithTargetAndReturnValue = action as IAction<TTarget, TReturnType>;
                if (actionWithTargetAndReturnValue != null)
                {
                    returnValue = actionWithTargetAndReturnValue.Execute(target);
                    return;
                }

                IActionMutable<TTarget, TReturnType> actionWithMutableTargetAndReturnValue = action as IActionMutable<TTarget, TReturnType>;
                if (actionWithMutableTargetAndReturnValue != null)
                {
                    returnValue = actionWithMutableTargetAndReturnValue.Execute(ref target);
                    return;
                }
            }
        }


    }
}
